﻿/*
 * Author: Arron Chapman
 * Author Contact: arron@arronchapman.com
 * Author Website: http://arronchapman.com
 * 
 * Project:MFDrivers
 * Project Website: http://mfdrivers.codeplex.com
 *
 * Creation Date: December 17th, 2011
 *
 * License: Apache 2.0
 * Copyright 2011 Arron Chapman

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 * 
 * Note: For the purposes of license attribution, keeping the above information in the file is adequate.
 * If you make any modifacations to this file and you think others might benefit from them, please email me at arron@arronchapman.com
 * 
 */

/*
 * Info: http://www.maxim-ic.com/datasheet/index.mvp/id/2781/t/al
 * Datasheet: http://datasheets.maxim-ic.com/en/ds/DS1806.pdf
 *
 */

/*Changelog
 * Date		| Editor		| Reason
 * 12/16/2011| Arron Chapman | Initial Draft
 * 12/21/2011| Arron Chapman | Revised the Set method, Added wiring diagram
 *
 */
using Microsoft.SPOT.Hardware;

namespace MFDrivers.DS1806
{
    ///   20 19 18 17 16 15 14 13 12 11
    ///   │  │  │  │  │  │  │  │  │  │
    /// ███████████████████████████████
    /// ▀██████████████████████████████
    ///   █████████████████████████████
    /// ▄██████████████████████████████
    /// ███████████████████████████████
    ///   │  │  │  │  │  │  │  │  │  │
    ///   1  2  3  4  5  6  7  8  9  10
    /// 
    /// 20  -> 3.3V
    /// 10  -> GND
    /// 8   -> CS
    /// 12  -> MOSI (D11)
    /// 9   -> CLK (D13)
    /// 11  -> Next IC 12  Note: Currently Unsupported
    /// 
    /// 

    public class DS1806
    {
        private readonly SPI _port;
        private readonly SPI.Configuration _spiConfig;
        private SPI.Configuration _oldConfig;
        
        public DS1806(SPI port, Cpu.Pin cs)
        {
            _port = port;

            _spiConfig = new SPI.Configuration(
                cs,
                true,
                1,
                0,
                false,
                true,
                1000, //1Mhz
                SPI.SPI_module.SPI1);
        }

        /// <summary>
        /// Reverses the bit order, 01010101 becomes 10101010
        /// </summary>
        /// <param name="x"></param>
        /// <returns></returns>
        private static int Reverse(int x)
        {
            ulong b = (ulong)x;
            b = ((b * 0x0802LU & 0x22110LU) | (b * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16;
            return (int)b;
        }

        /// <summary>
        /// Sets the value of pot to value.  
        /// </summary>
        /// <param name="pot">The pot to be adjusted 1-6</param>
        /// <param name="value">The new value for pot. 0 is Maximum, 63 is minimum resistance.</param>
        public void Set(int pot, int value)
        {
            //Store the old config so that you don't have to manualy adjust the spi.config every time you use Set
            _oldConfig = _port.Config;
            _port.Config = _spiConfig;

            byte[] message = new byte[6]; //8 bits for each of the 6 pots

            for (int i = 1; i < 7; i++) //once for each byte
            {
                byte data;

                if (pot == i)
                {
                    data = (byte)(Reverse(value));//value will be 00xxxxxx
                }
                else
                {
                    data = 192; //192 = 11000000 which means don't write 000000
                }

                message[i - 1] = data; //Add the byte to the message array
            }

            _port.Write(message);

            //Restore the old config.
            _port.Config = _oldConfig;
        }
    }
}
